#define NOMINMAX
#include "TreasuryFuturesData.h"
#include <algorithm>
#include <bondlib/BondCalendar.h>
#include <bondlib/SSVContainer.h>
#include <bondlib/RealTimeDeal/BondMarketStreamV2.h>
#include <bondlib/SSCTDTools.h>
#include <tfbondlib/BondFuture.h>
#include <qbtools/message/MessagePoster.h>
#include <qbprotocol/include/SSQBModel.h>
#include <qbkernel/include/qb_base.h>
#include <msgcenter/TFMsgProcess.h>
#include <core/Events.h>

#define  FIXED_FU_REAL_TIME -1

void CFixedNatFutureData::Clear()
{
	m_vctSort.clear();

	SCOPED_LOCK(m_lock);
	m_mapData.clear();
}

bool CFixedNatFutureData::SetQBPrice(xQBTFPriceList_c* pPrice)
{
	if (!pPrice) return false;
	bool bFindTF = false;
	std::vector<xQBTFPriceUnit_c> vctTen, vctFive, vctTwo;
	std::list<xQBTFPriceUnit_c>::const_iterator itrUnt = pPrice->m_List.begin();
	for (; itrUnt != pPrice->m_List.end(); itrUnt++){
		std::vector<xQBTFPriceUnit_c>& vctTemp = (strstr(itrUnt->m_InstrumentID, "TF") != nullptr) ? vctFive :
			((strstr(itrUnt->m_InstrumentID, "TS") != nullptr) ? vctTwo : vctTen);
		int nSz = (int)vctTemp.size();
		if (nSz == 0) vctTemp.push_back(*itrUnt);
		else if(nSz == 1){
			vctTemp.push_back(*itrUnt);
			if (itrUnt->m_OpenInterest > vctTemp[0].m_OpenInterest){
				vctTemp[1] = vctTemp[0];
				vctTemp[0] = *itrUnt;
			}
		}
		else if (nSz == 2){
			if (itrUnt->m_OpenInterest > vctTemp[0].m_OpenInterest){
				vctTemp[1] = vctTemp[0];
				vctTemp[0] = *itrUnt;
			}
			else if (itrUnt->m_OpenInterest > vctTemp[1].m_OpenInterest){
				vctTemp[1] = *itrUnt;
			}
		}
	}

	{
		SCOPED_LOCK(m_lock);
		m_mapData.clear();
		QString strTemp;
		for (int nL = 0; nL < 3; nL++) {
			std::vector<xQBTFPriceUnit_c>& vctTemp = (nL == 0) ? vctTen : ((nL == 1) ? vctFive : vctTwo);
			for (const auto& tmp : vctTemp) {
				strTemp = QString::asprintf("%s", tmp.m_InstrumentID);
				m_mapData[strTemp] = CFixedNatFutureTFData(tmp);
				if (!m_strCurrentTF.isEmpty() && m_strCurrentTF == strTemp) bFindTF = true;
			}
		}
	}
	
	m_vctSort.clear();
	for (int nS = 0; nS < 2; nS++){
		if ((int)vctTen.size() > nS) m_vctSort.push_back(QString(vctTen[nS].m_InstrumentID));
		if ((int)vctFive.size() > nS) m_vctSort.push_back(QString(vctFive[nS].m_InstrumentID));
		if ((int)vctTwo.size() > nS) m_vctSort.push_back(QString(vctTwo[nS].m_InstrumentID));
	}

	if (!bFindTF && !vctTen.empty()){
		m_strCurrentTF = QString::asprintf("%s", vctTen[0].m_InstrumentID);
		log_info("fixed nat future data init tf id:%s", vctTen[0].m_InstrumentID);
	}
	PushQBPrice(pPrice);
	return true;
}

bool CFixedNatFutureData::PushQBPrice(xQBTFPriceList_c* pPrice)
{
	bool bCurrent = false;
	if (!pPrice) return bCurrent;
	QString strTemp;
	std::list<xQBTFPriceUnit_c>::const_iterator itrUnt = pPrice->m_List.begin();

	SCOPED_LOCK(m_lock)
	for (; itrUnt != pPrice->m_List.end(); itrUnt++){
		strTemp = QString::asprintf("%s", itrUnt->m_InstrumentID);
		if (m_mapData.find(strTemp) != m_mapData.end()){
			bCurrent = true;
			m_mapData[strTemp].PushData(*itrUnt);
		}
	}
	return bCurrent;
}

void CFixedNatFutureData::SetQBTFTick(xQBTFTickList_c* pTick)
{
	if (!pTick) return;

	std::list<xQBTFTickUnit_c>::const_iterator itr = pTick->m_List.begin();
	QString strTFID = QString::asprintf("%s", itr->m_InstrumentID);
	if (m_mapData.find(strTFID) == m_mapData.end()){
		log_info("fixed nat future data tick can't find tf ：%s", itr->m_InstrumentID);
		return;
	}

	SCOPED_LOCK(m_lock)
	m_mapData[strTFID].SetTick(pTick);
}

void  CFixedNatFutureData::SetTFRealTimeData(xQBTFRealTimeList_c* pData)
{
	if (!pData) return;

	std::list<xQBTFRealTimeUnit_c>::const_iterator itr = pData->m_List.begin();
	QString strTFID = QString::asprintf("%s", itr->m_TF_ID);
	if (m_mapData.find(strTFID) == m_mapData.end()){
		log_info("fixed nat future data real time can't find tf ：%s", itr->m_TF_ID);
		return;
	}

	SCOPED_LOCK(m_lock);
	m_mapData[strTFID].SetReal(pData);
}

time_t CFixedNatFutureData::GetTickBeginTime(const QString& sTFID)
{
	CFixedNatFutureTFData tfData(false);
	bool succeed = GetData(sTFID, tfData);
	if (succeed) {
		return tfData.GetTickBeginTime();
	}
	return 0;
}

bool CFixedNatFutureData::GetCurrentData(CFixedNatFutureTFData& tfData)
{
	return GetData(m_strCurrentTF, tfData);
}

const QString& CFixedNatFutureData::GetCurrentTFID(){
	return m_strCurrentTF;
}

bool CFixedNatFutureData::GetData(const QString& strTF, CFixedNatFutureTFData& tfData) {
	SCOPED_LOCK(m_lock)
	if (!strTF.isEmpty()) {
		auto iter = m_mapData.find(strTF);
		if (iter != m_mapData.end()) {
			tfData = iter->second;
			return true;
		}
	}
	return false;
}

const QString& CFixedNatFutureData::GetSortTF(int idx) const
{
	if (idx >= 0 && idx < (int)m_vctSort.size()) {
		return m_vctSort[idx];
	}
	static QString str;
	return str;
}

void CFixedNatFutureData::fillRealTimePoint(const QString& TFID)
{
	SCOPED_LOCK(m_lock)
	for (auto itr = m_mapData.begin(); itr != m_mapData.end(); ++itr) {
		if (!TFID.isEmpty() && TFID != itr->first) {
			continue;
		}
		itr->second.TimerFillFrontLoop();
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
CFixedNatFutureTFData::CFixedNatFutureTFData(bool needInit/* = true*/)
{
	ResetDate();
	if (needInit) {
		Clear();
	}
}

CFixedNatFutureTFData::CFixedNatFutureTFData(const xQBTFPriceUnit_c& unit)
{
	ResetDate();
	Clear();
	m_strTFId = QString::asprintf("%s", unit.m_InstrumentID);
	SetPrice(unit);
}

void CFixedNatFutureTFData::ResetDate()
{
	m_nTodayDate = m_nYestodayDate = 0;
	//判断当日是否节假日
	m_bIsHoliday = CBondCalendar::instance().IsHoliday("CNY", "SSE", CSSVContainer::GetServerTime());

	//最近一个交易日
	time_t tToday = CSSVContainer::GetServerTime() + 60 * 60 * 24;
	SSCTDTools::GetPreTradingDay_SSE(tToday, true);
	QDateTime ctToday = QDateTime::fromTime_t(tToday);
	m_nTodayDate = ctToday.date().year() * 10000 + ctToday.date().month() * 100 + ctToday.date().day();

	//前一个交易日
	SSCTDTools::GetPreTradingDay_SSE(tToday, true);
	QDateTime ctYes = QDateTime::fromTime_t(tToday);
	m_nYestodayDate = ctYes.date().year() * 10000 + ctYes.date().month() * 100 + ctYes.date().day();
	QDateTime ctStart = QDateTime(ctYes.date(), QTime(9, 0, 0));
	m_tTickMax = ctStart.toTime_t();
}

void CFixedNatFutureTFData::Clear()
{
	InitialPoint();
	m_strTFId = "";
	m_strCTD = "";
	m_LastPrice = 0.0f;
	m_fVolumn = m_Hold = m_PreClosePrice = 0.0f;
	if (m_nYestodayDate > 0){
		QDateTime ctStart = QDateTime(QDate(m_nYestodayDate/10000, (m_nYestodayDate/100)%100, m_nYestodayDate%100), QTime(9,0,0));
		m_tTickMax = ctStart.toTime_t();
	}
	m_Param.Initial();
}

void CFixedNatFutureTFData::InitialPoint()
{
	m_mapPoint.clear();
	int nMinBegin = 14, nMinEnd = 15;

	int nBeginDate = CBondFuture::instance().GetChangeDate();
	int nCurDate = CMarketStream::GetBondDealInvalidateDay();

	if (nBeginDate > 0 && nBeginDate <= nCurDate) {
		nMinBegin = 29;
	}

	int nHour = 9, nMin = nMinBegin, nLooptime = 0;
	CFixedNatFuturePoint pt;
	while (true) {
		nLooptime++;
		if (nLooptime > 20000) {
			log_info("fixed nat future tf have a loop!");
			break;
		}
		m_mapPoint.insert(std::make_pair(nHour * 100 + nMin, pt));
		m_mapPointYes.insert(std::make_pair(nHour * 100 + nMin, pt));
		if (nHour == 15 && nMin == nMinEnd) break;
		if (nHour == 11 && nMin == 30) {
			nHour = 13;
			nMin = 1;
			continue;
		}
		if (nMin == 59) {
			nHour++;
			nMin = 0;
			continue;
		}
		nMin++;
	}
	// m_Param.m_nValidCount = m_mapPoint.size();
}

CFixedNatFutureTFData& CFixedNatFutureTFData::operator=(const CFixedNatFutureTFData& obj)
{
	m_mapPoint = obj.m_mapPoint;
	m_mapPointYes = obj.m_mapPointYes;
	m_strTFId = obj.m_strTFId;
	m_strCTD = obj.m_strCTD;
	m_LastPrice = obj.m_LastPrice;
	m_fVolumn = obj.m_fVolumn;
	m_Hold = obj.m_Hold;
	m_PreClosePrice = obj.m_PreClosePrice;
	m_tTickMax = obj.m_tTickMax;
	m_Param = obj.m_Param;

	m_nTodayDate = obj.m_nTodayDate;
	m_nYestodayDate = obj.m_nYestodayDate;
	m_bIsHoliday = obj.m_bIsHoliday;
	//m_ParamYes = obj.m_ParamYes;
	return *this;
}

void CFixedNatFutureTFData::PushData(const xQBTFPriceUnit_c& unt)
{
	SetPrice(unt);
}

void CFixedNatFutureTFData::SetReal(xQBTFRealTimeList_c* pReal)
{
	if (!pReal) return;
	std::list<xQBTFRealTimeUnit_c>::const_iterator itr = pReal->m_List.begin();
	int nPt = 0,nDate = 0;
	QString strTemp, strTemp2;
	for (; itr != pReal->m_List.end(); itr++){
		if (itr->m_Tran_Time <= 0) continue;
		QDateTime ctTime = QDateTime::fromTime_t(itr->m_Tran_Time);
		nPt = ctTime.time().hour() * 100 + ctTime.time().minute();
		strTemp = QString::asprintf("%02d:%02d:%02d", ctTime.time().hour(), ctTime.time().minute(), ctTime.time().second());
		nDate = ctTime.date().year() * 10000 + ctTime.date().month() * 100 + ctTime.date().day();
		bool bToday = (nDate == m_nTodayDate);
		std::map<int, CFixedNatFuturePoint>& mapPoint = bToday ? m_mapPoint : m_mapPointYes;
		CFixedNatWholeParam& pam = m_Param;// bToday ? m_Param : m_ParamYes;
		if (nPt > 0 && mapPoint.find(nPt) != mapPoint.end()){
			mapPoint[nPt].Update(itr->m_Close, itr->m_Volume, itr->m_Positions, strTemp.toStdString().c_str(), itr->m_Tran_Time_Msec, false, nPt, true, m_strTFId);
			FillToFront(nPt, 0, 0, "", 0, bToday);
			if (itr->m_Close > 0.0001){
				if (pam.m_dbMinPrc < 0.0001) {
					pam.m_dbMinPrc = itr->m_Close;
				} else {
					pam.m_dbMinPrc = std::min(pam.m_dbMinPrc, (double)itr->m_Close);
				}
				pam.m_dbMaxPrc = std::max(pam.m_dbMaxPrc, (double)itr->m_Close);
				pam.m_dbMaxVol = std::max(pam.m_dbMaxVol, (double)mapPoint[nPt].m_nVolum);
				pam.m_dbMaxOpenIn = std::max(pam.m_dbMaxOpenIn, mapPoint[nPt].m_dbOpenInt);
				if (pam.m_dbMinOpenIn < 0.0001) pam.m_dbMinOpenIn = itr->m_Positions;
				else pam.m_dbMinOpenIn = std::min(pam.m_dbMinOpenIn, itr->m_Positions);
			}
			m_tTickMax = std::max(m_tTickMax, (time_t)ctTime.toTime_t());
		}
	}
}

void CFixedNatFutureTFData::SetTick(xQBTFTickList_c* pTick)
{
	/*if (!pTick) return;
	int nHMax = 0, nMMax = 0, nSmax = 0;
	CString strTemp;
	CStringArray arrList;
	std::list<xQBTFTickUnit_c>::const_iterator itr = pTick->m_List.begin();
	int nPt = 0;
	for (; itr != pTick->m_List.end(); itr++){
		strTemp.Format(_T("%s"), SSA2W(itr->m_UpdateTime));
		CSSTools::Split(strTemp, _T(":"), arrList);
		if (arrList.GetSize() == 3){
			nHMax = max(nHMax, _ttoi(arrList[0]));
			nMMax = max(nMMax, _ttoi(arrList[1]));
			nSmax = max(nSmax, _ttoi(arrList[2]));
		}
		nPt = GetPointFromTime(itr->m_UpdateTime);
		if (nPt > 0 && m_mapPoint.find(nPt) != m_mapPoint.end()){
			if (itr->m_LastPrice > 0.0001){
				m_mapPoint[nPt].Update(itr->m_LastPrice, itr->m_LastVolume, itr->m_UpdateTime, itr->m_UpdateMillisec, false, nPt, true,m_strTFId);
				FillToFront(nPt, itr->m_LastPrice, itr->m_LastVolume, itr->m_UpdateTime, itr->m_UpdateMillisec);
				m_Param.m_dbMinPrc = min(m_Param.m_dbMinPrc, itr->m_LastPrice);
				m_Param.m_dbMaxPrc = max(m_Param.m_dbMaxPrc, itr->m_LastPrice);
				m_Param.m_dbMaxVol = max(m_Param.m_dbMaxVol, m_mapPoint[nPt].m_nVolum);
				m_Param.m_dbMinVol = 0;
			}
		}
	}
	if (nHMax > 0){
		time_t tTime = AfxGetBondContainer().GetServerTime();
		CTime ctTime(tTime);
		CTime ctMax = CTime(ctTime.GetYear(), ctTime.GetMonth(), ctTime.GetDay(), nHMax, nMMax, nSmax);
		m_tTickMax = ctMax.GetTime();
	}*/
}

void CFixedNatFutureTFData::SetPrice(const xQBTFPriceUnit_c& unt)
{
	m_PreClosePrice = unt.m_PreSettlementPrice;
	m_LastPrice = unt.m_LastPrice;
	m_fVolumn = unt.m_Volume;
	m_Hold = unt.m_OpenInterest;
	if (unt.m_Volume < 1) m_LastPrice = 0.0f;
	int nPt = GetPointFromTime(unt.m_UpdateTime);

	if (unt.m_InstrumentID == "T2303" && nPt==930) {
		int xx = 0;
	}

	if (m_mapPoint.find(nPt) != m_mapPoint.end()){
		//TODO 成交量的计算
		if (unt.m_LastPrice > 0.0001 && unt.m_Volume > 0 && unt.m_IncrementVolume > 0){
			m_mapPoint[nPt].Update(unt.m_LastPrice, unt.m_LastVolume, unt.m_OpenInterest,unt.m_UpdateTime, unt.m_UpdateMillisec, false, nPt, false, m_strTFId);
			FillToFront(nPt, unt.m_LastPrice, unt.m_LastVolume, unt.m_UpdateTime, unt.m_UpdateMillisec,true);
			if (m_Param.m_dbMinPrc < 0.0001) m_Param.m_dbMinPrc = unt.m_LastPrice;
			else m_Param.m_dbMinPrc = std::min(m_Param.m_dbMinPrc, (double)unt.m_LastPrice);
			m_Param.m_dbMaxPrc = std::max(m_Param.m_dbMaxPrc, (double)unt.m_LastPrice);
			m_Param.m_dbMaxVol = std::max(m_Param.m_dbMaxVol, (double)m_mapPoint[nPt].m_nVolum);
			m_Param.m_dbMaxOpenIn = std::max(m_Param.m_dbMaxOpenIn, unt.m_OpenInterest);
			if (m_Param.m_dbMinOpenIn < 0.0001) m_Param.m_dbMinOpenIn = unt.m_OpenInterest;
			else m_Param.m_dbMinOpenIn = std::min(m_Param.m_dbMinOpenIn, unt.m_OpenInterest);
			//if (m_Param.m_dbMinVol < 0.0001)  m_Param.m_dbMinVol = m_mapPoint[nPt].m_nVolum;
			//else m_Param.m_dbMinVol = min(m_Param.m_dbMinVol, m_mapPoint[nPt].m_nVolum);
		}
	}
	else{
		log_info("nat future tf data have a error time: %lld", unt.m_UpdateTime);
	}
}

void CFixedNatFutureTFData::LoadFrontValid(int & nValid, const int& nBegin, float& fPrice, bool bToday)
{
	nValid = nBegin;
	fPrice = 0.0f;
	std::map<int, CFixedNatFuturePoint>& mapPoint = bToday ? m_mapPoint : m_mapPointYes;
	std::map<int, CFixedNatFuturePoint>::const_iterator itr = mapPoint.find(nBegin);
	if (itr == mapPoint.end()) return;
	itr--;
	nValid = -1;
	fPrice = m_PreClosePrice;
	for (; itr != mapPoint.end(); itr--){
		if (!itr->second.IsFillPrice()){
			nValid = itr->first;
			fPrice = itr->second.m_fPrice;
			break;
		}
		if (itr == mapPoint.begin()){
			break;
		}
	}
}

void CFixedNatFutureTFData::FillToFront(int nBegin, float fPrc, int nVol, const char* cTime, int nSec, bool bToday)
{
	int nFrontValid = nBegin;
	float fPrice = -1;
	LoadFrontValid(nFrontValid, nBegin, fPrice, bToday);
	std::map<int, CFixedNatFuturePoint>& mapPoint = bToday ? m_mapPoint : m_mapPointYes;
	std::map<int, CFixedNatFuturePoint>::iterator itr = mapPoint.find(nFrontValid);
	if (itr == mapPoint.end()) itr = mapPoint.begin();
	else itr++;
	for (; itr != mapPoint.end() && itr->first <= nBegin; itr++){
		itr->second.Update(fPrice, 0, 0,"", 0, true, itr->first, false, m_strTFId);
	}
}

void CFixedNatFutureTFData::TimerFillFrontLoop()
{
	time_t tTime = CSSVContainer::GetServerTime();
	QDateTime ctTime = QDateTime::fromTime_t(tTime - 60);
	int nPt = ctTime.time().hour() * 100 + ctTime.time().minute();
	if (m_mapPoint.find(nPt) == m_mapPoint.end()){
		if (ctTime.time().hour() > 15 || (ctTime.time().hour() == 15 && ctTime.time().minute() > 15)){
			int nMinEnd = 15;
			nPt = 1500 + nMinEnd;
		}
	}
	FillToFront(nPt, 0, 0, "", 0,true);
}

int CFixedNatFutureTFData::GetPointFromTime(const char * cTime)
{
	int nReturn = 0;
	if (strlen(cTime) < 1) return nReturn;
	QString strTemp = QString::asprintf("%s", cTime);
	QStringList arrlist = strTemp.split(":");
	if (arrlist.size() != 3) return nReturn;
	nReturn = arrlist[0].toInt() * 100 + arrlist[1].toInt();
	return nReturn;
}

time_t CFixedNatFutureTFData::GetTickBeginTime()
{
	return m_tTickMax;
}

void CFixedNatFutureTFData::LoadWholeParam(CFixedNatWholeParam& param, bool bYestoday)
{
	param = m_Param;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
CFixedNatFuturePoint::CFixedNatFuturePoint()
{
	Clear();
}

CFixedNatFuturePoint::~CFixedNatFuturePoint()
{
}

void CFixedNatFuturePoint::Clear()
{
	m_fPrice = 0.0f;
	m_dbOpenInt = 0.0f;
	m_nVolum = 0;
	m_mapPriceReal.clear();
}

CFixedNatFuturePoint & CFixedNatFuturePoint::operator = (const CFixedNatFuturePoint& obj){
	m_fPrice = obj.m_fPrice;
	m_nVolum = obj.m_nVolum;
	m_dbOpenInt = obj.m_dbOpenInt;
	m_mapPriceReal = obj.m_mapPriceReal;
	return *this;
}

void CFixedNatFuturePoint::Update(float fPrc, int nVol, double dbOpenInt, const char* cTime, int nSec, bool isFill, int nPosition, bool bRealTime, const QString& strTF)
{
	if (isFill){
		if (m_mapPriceReal.empty()){
			m_fPrice = fPrc;
			m_nVolum = 0;
			m_dbOpenInt = 0.0f;
		}
		return;
	}
	int nCurSec = LoadSecTime(cTime, nSec);
	if (bRealTime){
		m_mapPriceReal[FIXED_FU_REAL_TIME] = FUPRI_VOL(fPrc, nVol, dbOpenInt,nCurSec);
	}
	else{
		m_mapPriceReal[nCurSec] = FUPRI_VOL(fPrc, nVol, dbOpenInt, nCurSec);
	}
	MergePrc();
}

void CFixedNatFuturePoint::MergePrc()
{
	int nSz = m_mapPriceReal.size();
	if (nSz <= 0)return;
	if (m_mapPriceReal.find(FIXED_FU_REAL_TIME) != m_mapPriceReal.end()){
		const FUPRI_VOL& fupReal = m_mapPriceReal[FIXED_FU_REAL_TIME];
		m_fPrice = m_mapPriceReal[FIXED_FU_REAL_TIME].m_fPrice;
		m_nVolum = m_mapPriceReal[FIXED_FU_REAL_TIME].m_nVolumn;
		m_dbOpenInt = m_mapPriceReal[FIXED_FU_REAL_TIME].m_dbOpenInte;
		for (std::map<int, FUPRI_VOL>::const_iterator itr = m_mapPriceReal.begin(); itr != m_mapPriceReal.end(); itr++){
			if (itr->first != FIXED_FU_REAL_TIME){
				if (itr->first > fupReal.m_nSec){
					m_fPrice = itr->second.m_fPrice;
					m_nVolum += itr->second.m_nVolumn;
					m_dbOpenInt = itr->second.m_dbOpenInte;
				}
			}
		}
	}
	else {
		m_fPrice = 0.0f;
		m_nVolum = 0;
		m_dbOpenInt = 0.0f;
		for (std::map<int, FUPRI_VOL>::const_iterator itr = m_mapPriceReal.begin(); itr != m_mapPriceReal.end(); itr++){
			m_fPrice = itr->second.m_fPrice;
			m_nVolum += itr->second.m_nVolumn;
			m_dbOpenInt = itr->second.m_dbOpenInte;
		}
	}
}

int CFixedNatFuturePoint::LoadSecTime(const char * cTime, int nSec)
{
	int nLen = strlen(cTime);
	if (nLen > 2){
		const char* cSec = cTime + nLen - 2;
		if (cSec != nullptr){
			int nRt = atoi(cSec) * 1000 + nSec;
			return nRt;
		}
	}
	return nSec;
}

bool CFixedNatFuturePoint::IsFillPrice() const
{
	return m_mapPriceReal.size()<=0 || m_fPrice<0.001;
}

//////////////////////////////////////////////////////////////////////////
FixedNatFutureHandler::FixedNatFutureHandler(CFixedNatFutureData* data)
	: m_data(data)
{
	m_handler = msgEventDispatcher.appendListener(EVENT_MESSAGE_ARRIVED, [this](const qb::SSAckMsg* msg) {
		if (msg->m_FuncID == E_FID_QB_MARKET_STREAM_DEAL_REQ || msg->m_FuncID == E_FID_QB_MARKET_STREAM_DEAL_PUSH)
		emit recvData(msg->m_FuncID);
		});
}

FixedNatFutureHandler::~FixedNatFutureHandler()
{
	msgEventDispatcher.removeListener(EVENT_MESSAGE_ARRIVED, m_handler);
}

void FixedNatFutureHandler::reqTFPrice()
{
	CFutureArray& futureArray = CBondFuture::instance().GetFutureArray();
	xQBTFInstrument_c insru;
	memset(&insru, 0, sizeof(xQBTFInstrument_c));
	QString strTemp, strOut = "fixed income reload data: ";
	for (std::vector<CFutureInfo>::const_iterator itor = futureArray.m_data.begin(); itor!=futureArray.m_data.end(); ++itor) {
		if (strcmp(itor->m_Is_Tradable, "Y") == 0) {
			FIELDCOPY(insru.m_InstrumentID, itor->m_TF_ID);
			FIELDCOPY(insru.m_TF_Key, itor->m_TF_Key);
			m_prcReq.m_List.push_back(insru);
			strTemp = QString::asprintf("%s|", insru.m_InstrumentID);
			strOut += strTemp;
		}
	}

	if (!m_prcReq.m_List.empty()) {
		qb::SSRequestMsg msg;
		msg.m_FuncID = E_FID_QB_TF_PRICE_REQ_V2;
		msg.m_pRequest = &m_prcReq;
		MessagePoster poster(&msg, qbmsg::tf::EncodeFunc);
		poster.send(this);

		PushMsgInfo pmi(E_FID_QB_TF_PRICE_PUSH_V3, "", nullptr);
		msg.m_FuncID = E_FID_QB_TF_PRICE_PUSH_V3;
		registPush(pmi, &msg, qbmsg::tf::EncodeFunc);
	}

	log_info(strOut.toStdString().c_str());
}

void FixedNatFutureHandler::cancelReqTFPrice()
{
	if (!m_prcReq.m_List.empty()) {
		qb::SSRequestMsg msg;
		msg.m_FuncID = E_FID_QB_TF_PRICE_PUSH_CANCEL_V3;
		msg.m_pRequest = &m_prcReq;
		MessagePoster poster(&msg, nullptr);
		poster.send();
	}
}

void FixedNatFutureHandler::reqRealtimeData(const QString& TFID)
{
	if (!m_data ||
		TFID.isEmpty() ||
		m_setTickReq.find(TFID)!=m_setTickReq.end()) {
		emit recvData(E_FID_QB_TF_REALTIME);
		return;
	}

	m_setTickReq.insert(TFID);
	xQBTFRealTimeReq_t reqTime;
	memset(&reqTime, 0, sizeof(xQBTFRealTimeReq_t));
	{
		CFutureInfo fuInfo;
		if (CBondFuture::instance().GetFutureInfo(TFID.toStdString().c_str(), &fuInfo)) {
			FIELDCOPY(reqTime.m_TF_Key, fuInfo.m_TF_Key);
		}
	}
	FIELDCOPY(reqTime.m_TF_ID, TFID.toStdString().c_str());
	reqTime.m_beginTime = m_data->GetTickBeginTime(TFID);
	reqTime.m_beginTime = std::max(reqTime.m_beginTime-300, (time_t)0);
	reqTime.m_endTime = 0;
	qb::SSRequestMsg msg;
	msg.m_FuncID = E_FID_QB_TF_REALTIME;
	msg.m_pRequest = &reqTime;
	MessagePoster poster(&msg, qbmsg::tf::EncodeFunc);
	poster.send(this);
}

void FixedNatFutureHandler::clearData()
{
	m_prcReq.m_List.clear();
	m_setTickReq.clear();
	if (m_data){
		m_data->Clear();
	}
}

void FixedNatFutureHandler::onDataArrived(const qb::SSAckMsg& msg)
{
	int funcId = msg.m_FuncID;
	switch (funcId) {
	case E_FID_QB_TF_PRICE_REQ_V2: {
		xQBTFPriceList_c* ret = (xQBTFPriceList_c*)msg.m_pRet;
		if (!ret) return;
		if (msg.m_IsReceving == 0) {
			m_data->SetQBPrice(ret);
			emit recvData(funcId);
		}
		break;
	}
	case E_FID_QB_TF_PRICE_PUSH_V3: {
		xQBTFPriceList_c* ret = (xQBTFPriceList_c*)msg.m_pRet;
		if (!ret) return;
		m_data->PushQBPrice(ret);
		emit recvData(funcId);
		break;
	}
	case E_FID_QB_TF_REALTIME: {
		xQBTFRealTimeList_c* ret = (xQBTFRealTimeList_c*)msg.m_pRet;
		if (!ret) return;
		m_data->SetTFRealTimeData(ret);
		if (msg.m_IsReceving == 0) {
			auto itr = ret->m_List.begin();
			if (itr != ret->m_List.end()) {
				fillRealTimePoint(itr->m_TF_ID);
			}
			emit recvData(funcId);
		}
		break;
	}
	default:
		break;
	}
}

void FixedNatFutureHandler::fillRealTimePoint(const QString& TFID)
{
	m_data->fillRealTimePoint(TFID);
}

